var log = require('oil/log');

var narcissus = require('narcissus');

// Given a script node, extracts the require() statements at the top of it
//
// TODO:
//   - Go by blocks -- if the first one looks like require(), then issue
//     hard errors for any deviations
//   - Write unit tests for this function, especially the offsets
//
//   Returns:
//      TODO: describe

var parseDeps = exports.parseDeps = function(codeStr) {
  var parsed = narcissus.parse(codeStr);
  return extractDeps(parsed.toJSON());
}

var extractDeps = exports.extractDeps = function(scriptNode) {

  // array of {varName, modName}
  var deps = [],
      offset = 0;

  // TODO: Expose SCRIPT type
  if (scriptNode.type !== 'SCRIPT') {
    throw {
      name: 'InvalidParseTree',
      message: 'Expected SCRIPT, got ' + type
    };
  }

  // For empty scripts
  if (scriptNode.children === undefined) {
    scriptNode.children = [];
  }

  for (var i=0; i<scriptNode.children.length; i++) {
    var aborted = false;
    var varNode = scriptNode.children[i].toJSON();
    if (varNode.type !== 'var') {
      log.info('Quitting after %s var statements', i+1);
      break;
    }

    log.info('var node');
    log.push();

    var childOffset = 0;

    for (var j=0; j<varNode.children.length; j++) {
      var child = varNode.children[j].toJSON();
      if (!child.initializer) {
        log.info('No initializer for variable %s', child.name);
        aborted = true;
        break;
      }

      var value = child.initializer.toJSON();

      log.info('child %s %s', child.name, value.type);
      var dep = {varName: child.name, modName: null, deps: []};

      if (value.type !== 'CALL' && value.a !== 'require') {
        log.info('Expected a require call, got %s', value.type);
        aborted = true;
        break;
      }

      var args = value.b.toJSON();
      if (args.type !== 'LIST') {
        log.info('Expected an argument list , got %s', args.type);
        aborted = true;
        break;
      }

      // Just take the first argument
      // TODO: There's a 2-argument require
      for (var k=0; k<args.children.length; k++) {
        var arg = args.children[k].toJSON();
        // TODO: Enforce that it's the first one?
        if (k === 0 && arg.type === 'STRING') {
          dep.modName = arg.value;
          deps.push(dep);
        }
      }

      // Set it each time
      log.info('SETTING %s', value.end);
      childOffset = value.end;
    }

    log.pop();

    if (aborted) {
      break;
    } else {
      // We processed every assignment foo = require('foo') in the var block 
      // So this means that we can slice this entire block off
      offset = childOffset;
      log.info('OFFSET %s', offset);
    }
  }
  return {deps: deps, offset: offset};
};
